Getting started
Quick start
julia> using Tensorial
julia> x = Vec{3}(rand(3)); # constructor similar to SArray.jl
julia> A = @Mat rand(3,3); # @Vec, @Mat and @Tensor, analogous to @SVector, @SMatrix and @SArray
julia> A ⊡ x ≈ A * x # single contraction (⊡)
true
julia> A ⊡₂ A ≈ A ⋅ A # double contraction (⊡₂)
true
julia> x ⊗ x ≈ x * x' # tensor product (⊗)
true
julia> (@einsum y := x[i] * A[j,i] * x[j]) ≈ x ⊡ A' ⊡ x # Einstein summation (@einsum)
true
julia> As = rand(Tensor{Tuple{@Symmetry{3,3}}}); # specify symmetry S₍ᵢⱼ₎
julia> AAs = rand(Tensor{Tuple{@Symmetry{3,3}, @Symmetry{3,3}}}); # SS₍ᵢⱼ₎₍ₖₗ₎
julia> inv(AAs) ⊡₂ As ≈ @einsum Bs[i,j] := inv(AAs)[i,j,k,l] * As[k,l] # it just works
true
julia> δ = one(Mat{3,3}) # identity tensor
3×3 Tensor{Tuple{3, 3}, Float64, 2, 9}: 1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0
julia> gradient(identity, As) ≈ one(AAs) # ∂Asᵢⱼ/∂Asₖₗ = (δᵢₖδⱼₗ + δᵢₗδⱼₖ) / 2
true
Defining tensors
1. Tensor
All tensors in Tensorial.jl are represented by the type Tensor{S, T, N, L}
, where each type parameter represents the following:
S
: The size ofTensor
s which is specified by usingTuple
(e.g., 3×2 tensor becomesTensor{Tuple{3,2}}
).T
: The type of element which must beT <: Real
.N
: The number of dimensions (the order of tensor).L
: The number of independent components.
The type parameters N
and T do not need to be specified when Constructing tensors, as they can be inferred from the size of tensor S
. However, when defining Tensor
s in a struct
, it is necessary to declare all type parameters to avoid type instability, as follows:
struct MyBadType{T} # all bad
A::Tensor{Tuple{3,3}, Float64}
B::Tensor{Tuple{3,3}, T}
C::Tensor{Tuple{@Symmetry{3,3}}, T, 2}
end
struct MyGoodType{T, dim, L, TT <: Tensor} # all good
A::Tensor{Tuple{3,3}, Float64, 2, 9}
B::Tensor{Tuple{3,3}, T, 2, 9}
C::Tensor{Tuple{@Symmetry{dim,dim}}, T, 2, L}
D::TT
end
The type parameters N
and L
can be checked using the @Tensor
macro as follows:
julia> @Tensor{Tuple{@Symmetry{3,3,3}}}
Tensor{Tuple{Symmetry{Tuple{3, 3, 3}}}, T, 3, 10} where T
2. Symmetry
Specifying the symmetry of a tensor can improve performance, as Tensorial.jl eliminates duplicate computations. Symmetries can be applied using Symmetry
in the type parameter S
(e.g., Symmetry{Tuple{3,3}}
). The @Symmetry
macro simplifies this process by allowing you to omit Tuple
, as in @Symmetry{3,3}
. Below are some examples of how to specify symmetries:
- $A_{(ij)}$ with 3x3:
Tensor{Tuple{@Symmetry{3,3}}}
- $A_{(ij)k}$ with 3x3x3:
Tensor{Tuple{@Symmetry{3,3}, 3}}
- $A_{(ijk)}$ with 3x3x3:
Tensor{Tuple{@Symmetry{3,3,3}}}
- $A_{(ij)(kl)}$ with 3x3x3x3:
Tensor{Tuple{@Symmetry{3,3}, @Symmetry{3,3}}}
where the bracket $()$ in the indices denotes the symmetry.
Aliases
const Vec{dim, T} = Tensor{Tuple{dim}, T, 1, dim}
const Mat{m, n, T, L} = Tensor{Tuple{m, n}, T, 2, L}
const SecondOrderTensor{dim, T, L} = Tensor{NTuple{2, dim}, T, 2, L}
const FourthOrderTensor{dim, T, L} = Tensor{NTuple{4, dim}, T, 4, L}
const SymmetricSecondOrderTensor{dim, T, L} = Tensor{Tuple{@Symmetry{dim, dim}}, T, 2, L}
const SymmetricFourthOrderTensor{dim, T, L} = Tensor{NTuple{2, @Symmetry{dim, dim}}, T, 4, L}